package b3d.geometry
{
	import flash.utils.Dictionary;

	public class MeshUtils
	{
		public function MeshUtils()
		{
			
		}
		public static function generateVertexNormals(mesh:Mesh3D):void
		{
			mesh.normals = new Vector.<Number>();
			var normals:Vector.<Number> = mesh.normals;
			var triangles:Vector.<Vector.<uint>> = generateSharedTriangles(mesh);
			var edges:Vector.<Number> = generateEdges(mesh);
			var faceNormals:Vector.<Number> = generateFaceNormals(mesh, edges);
			var vertices:Vector.<Number> = mesh.vertices;
			for(var i:int = 0; i < vertices.length/3; i++)
			{
				//var vertexNormal:VectorB3D = new VectorB3D();
				var normalx:Number = 0;
				var normaly:Number = 0;
				var normalz:Number = 0;
				for(var j:int = 0; j < triangles[i].length; j++)
				{	
					normalx += faceNormals[triangles[i][j]*3];
					normaly += faceNormals[(triangles[i][j]*3)+1];
					normalz += faceNormals[(triangles[i][j]*3)+2];
				}
				var length:Number = Math.sqrt((normalx*normalx)+(normaly*normaly)+(normalz*normalz));
				normalx = normalx/(length) || 0;
				normaly = normaly/(length) || 0;
				normalz = normalz/(length) || 0;
				
				length = Math.sqrt((normalx*normalx)+(normaly*normaly)+(normalz*normalz));
				normals.push(normalx, normaly, normalz);
				//				if(i%3 == 0)normals.push(1, 0, 0);
				//				else if(i%2 == 0)normals.push(0, 1, 0);
				//				else normals.push(0, 0, 1);
				
			}			
			triangles = null;
			faceNormals = null;
		}
		public static function generateSharedTriangles(mesh:Mesh3D):Vector.<Vector.<uint>>
		{
			var triangles:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>(mesh.ids.length);
			var ids:Vector.<uint> = mesh.ids;
			for(var i:int = 0; i < mesh.vertices.length/3; i++)
			{
				triangles[i] = new Vector.<uint>();
			}
			trace(mesh.vertices.length);
			trace(triangles.length);
			trace(mesh.ids.length);
			
			for(i = 0; i < ids.length; i+=3)
			{
				var a:int = ids[i];
				var b:Vector.<uint> = triangles[a];
				triangles[ids[i]].push(i/3);
				triangles[ids[i+1]].push(i/3);
				triangles[ids[i+2]].push(i/3);
			}
			return triangles;
		}
		public static function generateFaceNormals(mesh:Mesh3D, edges:Vector.<Number>):Vector.<Number>
		{
			var faceNormals:Vector.<Number> = new Vector.<Number>();
			var ids:Vector.<uint> = mesh.ids;
			for(var i:int = 0; i < ids.length; i+=3)
			{
				var id0:int = ids[i];
				var id1:int = ids[i+1];
				var id2:int = ids[i+2];
				
				var edge0x:Number = edges[(i*3)];
				var edge0y:Number = edges[(i*3)+1]
				var edge0z:Number = edges[(i*3)+2]
				
				var edge1x:Number = edges[((i+2)*3)];
				var edge1y:Number = edges[((i+2)*3)+1];
				var edge1z:Number = edges[((i+2)*3)+2];
				
				var normalx:Number = (edge0y*edge1z) - (edge0z*edge1y);
				var normaly:Number = (edge0z*edge1x) - (edge0x*edge1z);
				var normalz:Number = (edge0x*edge1y) - (edge0y*edge1x);
				
				
				var length:Number = Math.sqrt((normalx*normalx)+(normaly*normaly)+(normalz*normalz));
				normalx = normalx/(length) || 0;
				normaly = normaly/(length) || 0;
				normalz = normalz/(length) || 0;
				
				faceNormals.push(normalx, normaly, normalz);
			}
			return faceNormals;
		}
		public static function generateEdges(mesh:Mesh3D):Vector.<Number>
		{
			var edges:Vector.<Number> = new Vector.<Number>();
			var ids:Vector.<uint> = mesh.ids;
			var vertices:Vector.<Number> = mesh.vertices;
			
			for(var i:int = 0; i < ids.length; i+=3)
			{
				var id0:int = ids[i];
				var id1:int = ids[i+1];
				var id2:int = ids[i+2];
				
				var edge0x:Number = vertices[id0*3] - vertices[id1*3];
				var edge0y:Number = vertices[(id0*3)+1] - vertices[(id1*3)+1];
				var edge0z:Number = vertices[(id0*3)+2] - vertices[(id1*3)+2];
				
				var edge1x:Number = vertices[id1*3] - vertices[id2*3];
				var edge1y:Number = vertices[(id1*3)+1] - vertices[(id2*3)+1];
				var edge1z:Number = vertices[(id1*3)+2] - vertices[(id2*3)+2];
				
				var edge2x:Number = vertices[id2*3] - vertices[id0*3];
				var edge2y:Number = vertices[(id2*3)+1] - vertices[(id0*3)+1];
				var edge2z:Number = vertices[(id2*3)+2] - vertices[(id0*3)+2];
				
				edges.push(edge0x, edge0y, edge0z, edge1x, edge1y, edge1z, edge2x, edge2y, edge2z);				
			}	
			return edges;
		}
		public static function merge(destination:Mesh3D, source:Mesh3D):void
		{
			var vertCache:Dictionary = new Dictionary();
			var uvCache:Dictionary = new Dictionary();
			
			var idsCache:Dictionary = new Dictionary();
			var numIds:int = destination.ids.length;
			
			var dstVerts:Vector.<Number> = destination.vertices;
			var dstUvs:Vector.<Number> = destination.uvs;
			var dstIds:Vector.<uint> = destination.ids;
			
			
			for(var i:int = 0; i < dstVerts.length; i+=3)
			{
				var hash:String = dstVerts[i]+","+dstVerts[i+1]+","+dstVerts[i+2];
				trace(hash);
				vertCache[hash] = i/3;
			}
			for(var i:int = 0; i < dstUvs.length; i+=2)
			{
				var hash:String = dstUvs[i]+","+dstUvs[i+1];
				uvCache[hash] = i/2;
			}
			
			var srcVerts:Vector.<Number> = source.vertices;
			var srcUvs:Vector.<Number> = source.uvs;
			var srcIds:Vector.<uint> = source.ids;
			
			trace(destination.vertices.length);
			trace(dstVerts.length);
			var push:int;
			var numMatches:int;
			for(var i:int = 0; i < srcVerts.length; i+=3)
			{
				var verthash:String = srcVerts[i]+","+srcVerts[i+1]+","+srcVerts[i+2];
				trace(verthash);
				if(vertCache[verthash] != undefined)
				{
					var uvhash:String = srcUvs[(i/3)*2]+","+srcUvs[((i/3)*2)+1];
					if(uvCache[uvhash] != undefined)
					{
						idsCache[i/3] = vertCache[hash];
						numMatches++;
					}					
				}else{
					push++;
					dstVerts.push(srcVerts[i],srcVerts[i+1],srcVerts[i+2]);
					dstUvs.push(srcUvs[(i/3)*2],srcUvs[((i/3)*2)+1]);
				}
			}
			trace(destination.vertices.length);
			trace(dstVerts.length);
			for(var i:int = 0; i < srcIds.length; i++)
			{
				if(idsCache[srcIds[i]] == undefined)
				{
					dstIds.push(numIds-1+srcIds[i]);
				}
			}
			trace(destination.vertices.length);
			trace(dstVerts.length);
			
			trace("push",push);
			trace("numMatches",numMatches);
			destination.vertices = dstVerts;
			generateVertexNormals(destination);		
		}
	}
}